package ru.ifmo.tanya.service.impl;

import org.jdom.Element;
import ru.ifmo.tanya.core.calls.Call;
import ru.ifmo.tanya.core.calls.CallManager;
import ru.ifmo.tanya.core.users.User;
import ru.ifmo.tanya.service.XmlService;
import ru.ifmo.tanya.util.Pair;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * User: nikart
 * Date: 5/22/13
 * Time: 3:21 PM
 */
public class ShowCallHistogramService extends XmlService {

    public static final long WEEK = 1000L * 60 * 60 * 24 * 7;
    private final CallManager callManager = new CallManager();

    @Override
    public void invoke(User user, HttpServletRequest request, Element response) {
        List<Call> allCalls = callManager.getAllCalls();
        SortedMap<Integer, Integer> callsByHour = getCallsByHour(allCalls);
        String result = createStringFromMap(callsByHour);
        response.addContent(new Element("graph-data").addContent(result));
        SortedMap<Date, Pair<Double, Double>> dayToCallNum = getDayToCallNum(allCalls);
        response.addContent(new Element("graph-data2").addContent(day2CallNumString(dayToCallNum)));
    }

    private String createStringFromMap(SortedMap<Integer, Integer> map) {
        StringBuilder builder = new StringBuilder("[['Дата', 'Количество звонков']");
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            String hourString = entry.getKey() + ":00";
            if (entry.getKey() < 10) {
                hourString = "0" + hourString;
            }
            builder.append(", ['").append(hourString).append("', ").append(entry.getValue()).append("]");
        }
        builder.append("]");
        return builder.toString();
    }

    private String day2CallNumString(SortedMap<Date, Pair<Double, Double>> map) {
        StringBuilder result = new StringBuilder("[['Дата', 'Процент звонков с ожиданием менее 5 минут', 'Процент звонков с ожиданием менее 10 минут']");
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
        for (final Map.Entry<Date, Pair<Double, Double>> entry : map.entrySet()) {
            result.append(", ['")
                    .append(dateFormat.format(entry.getKey())).append("', ")
                    .append(entry.getValue().getFirst()).append(", ")
                    .append(entry.getValue().getSecond()).append("]");
        }

        result.append("]");
        return result.toString();
    }

    private SortedMap<Integer, Integer> getCallsByHour(List<Call> calls) {
        Calendar calendar = Calendar.getInstance();
        SortedMap<Integer, Integer> result = new TreeMap<>();
        for (int i = 0; i <= 24; i += 2) {
            result.put(i, 0);
        }
        for (Call call : calls) {
            calendar.setTime(call.getCreationTime());
            int hour = calendar.get(Calendar.HOUR);
            Integer count = result.get(hour + 2 - hour % 2);
            result.put(hour + 2 - hour % 2, count + 1);
        }
        return result;
    }

    private SortedMap<Date, Pair<Double, Double>> getDayToCallNum(List<Call> allCalls) {
        Date from = new Date(System.currentTimeMillis() - WEEK);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(from);
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        Date start = calendar.getTime();
        SortedMap<Date, Pair<Double, Double>> result = new TreeMap<>();
        Map<Date, List<Call>> callsByDate = groupCallsByDate(allCalls);
        for (final Map.Entry<Date, List<Call>> entry : callsByDate.entrySet()) {
            if (entry.getKey().after(start) || entry.getKey().equals(start)) {
                List<Call> value = entry.getValue();
                int lessThan5Min = 0;
                int lessThan10Min = 0;
                for (Call call : value) {
                    long waitingMillis = call.getAnswerTime().getTime() - call.getCreationTime().getTime();
                    if (waitingMillis < 1000 * 60 * 5) {
                        ++ lessThan5Min;
                    }
                    if (waitingMillis < 1000 * 60 * 10) {
                        ++ lessThan10Min;
                    }
                }
                result.put(entry.getKey(), Pair.create(lessThan5Min * 100.0 / value.size(), lessThan10Min * 100.0 / value.size()));
            }
        }

        return result;
    }

    private Map<Date, List<Call>> groupCallsByDate(List<Call> calls) {
        Map<Date, List<Call>> result = new HashMap<>();
        for (Call call : calls) {
            Date creationTime = new Date(call.getCreationTime().getTime());
            creationTime.setHours(0);
            creationTime.setMinutes(0);
            creationTime.setSeconds(0);
            List<Call> callsByDate = result.get(creationTime);
            if (callsByDate == null) {
                callsByDate = new ArrayList<>();
                result.put(creationTime, callsByDate);
            }
            callsByDate.add(call);
        }
        return result;
    }

    @Override
    public String getXslFilePath() {
        return "/xsl/show_call_hist.xsl";
    }
}
